JavaScript Class Fundamentals

Summary: in this tutorial, you will learn about the JavaScript class and how to create classes in ES6.

Classes prior to ES6 revisited

Prior to ES6, JavaScript had no classes. To mimic a class, we often use a constructor function as shown in the following example: function Animal(type) { this.type = type; } Animal.prototype.identify = function() { console.log(this.type); } var cat = new Animal('Cat'); cat.identify(); // Cat How it works.

JavaScript class declaration

ES6 introduced a new syntax for creating a class as shown in this example. class Animal { constructor(type) { this.type = type; } identify() { console.log(this.type); } } let cat = new Animal('Cat'); cat.identify(); This Animal class behaves like the Animal type in the previous example. However, instead of using a constructor function, it uses the class keyword. In the Animal class, the constructor() is where you can add the properties of an instance. The identify() is the method of the Animal class. Note that you don’t need to use the function keyword to declare a method of the class. The class declaration is just syntactic sugar of the constructor function, therefore, the result of the typeof operator of the Animal class is function. console.log(typeof Animal); // function In addition, the relationship between the identify() method and Animal class is the same as the relationship between the identify() method and the Animal.prototype in the previous example.

Syntactic sugar is syntax in JavaScript programming language designed to make things easier to express more clearly and concisely.

Class vs. custom type

Despite the similarities between a class a custom type defined via a constructor function, there are some important differences. First, class declarations are not hoisted like function declarations. For example, if you place the following code above the Animal class declaration section, you will get a ReferenceError. let dog = new Animal('Dog'); // Uncaught ReferenceError: Animal is not defined Second, all the code inside a class automatically executes in the strict mode, and you cannot change this behavior. Third, class methods are non-enumerable. If you use a constructor function, you have to use the Object.defineProperty() method to make a property non-enumerable. Fourth, calling the class constructor without the new operator will result in an error as shown in the following example. let duck = Animal('Duck'); // Uncaught TypeError: Class constructor Animal cannot be invoked without 'new'

JavaScript class expressions

Similar to functions, classes have expression forms too. A class expression does not require an identifier after the class keyword. You can use a class expression in a variable declaration and pass it into a function as an argument. Here is a class expression that is equivalent to the previous Animal class example: let Animal = class { constructor(type) { this.type = type; } identify() { console.log(this.type); } } let duck = new Animal('Duck'); console.log(duck instanceof Animal); // true console.log(duck instanceof Object); // true console.log(typeof Animal); // function console.log(typeof Animal.prototype); // function Similar to function expressions, class expressions are not hoisted.

First-class citizen

JavaScript class is a first-class citizen. It means that you can pass a class into a function, return it from a function, and assign it to a variable. See the following example: function factory(aClass) { return new aClass(); } let greeting = factory(class { sayHi() { console.log('Hi'); } }); greeting.sayHi(); // 'Hi' In this example, the factory() function takes an anonymous class expression as an argument. It creates an instance of that class and returns the instance.

Singleton

You can use the class expression to create singleton by calling the class constructor immediately. To do this, you use the new operator with a class expression and include the parentheses at the end of class declaration as in the following example. let app = new class { constructor(name) { this.name = name; } start() { console.log(`Starting the ${this.name}...`); } }('Awesome App'); app.start(); // Starting the Awesome App... In this example, we create an anonymous class expression and execute it immediately.

Getter and setter

To create a getter and setter, you use get and set keywords followed by a space and an identifier. See the following example: class Person { constructor(firstName, lastName) { this.firstName = firstName; this.lastName = lastName; } get fullName() { return this.firstName + ' ' + this.lastName; } set fullName(str) { let names = str.split(' '); if (names.length === 2) { this.firstName = names[0]; this.lastName = names[1]; } else { throw 'Invalid name format'; } } } let mary = new Person('Mary', 'Doe'); console.log(mary.fullName); // Mary Doe // set new name mary.fullName = 'Mary William'; console.log(mary.fullName); // Mary William The Person class has the property fullName as a getter and setter. The fullName getter returns the full name of a person object by concatenating the first name, space, and last name. The fullName setter accepts a string as an argument. The setter method splits the string into parts and assigns the firstName and lastName properties the appropriate parts. If the input argument is not in the correct format i.e., first name, space, and last name, the setter method throws an error.

Computed member names

Like an object literal, you can use computed names for properties of a class. The following Person class is equivalent to the Person class in the previous example except that it uses the name as the computed getter and setter. let name = 'fullName'; class Person { constructor(firstName, lastName) { this.firstName = firstName; this.lastName = lastName; } get[name]() { return this.firstName + ' ' + this.lastName; } set[name](str) { //... } } var john = new Person('John', 'Doe'); console.log(john.fullName); // John Doe

Static methods

Prior to ES6, to create a static method, you add the method directly to the constructor. For example, the following adds a static method to the Animal type: Animal.make = function(type) { return new Animal(type); } var dog = Animal.make('Dog'); dog.identify(); // Dog The make() method is considered a static method because it doesn’t depend on any instance of the Animal for its property values. ES6 simplified this by using the static notation before the method name as shown in the following example: class Animal { constructor(type) { this.type = type; } identify() { console.log(this.type); } static create(type) { return new Animal(type); } } var mouse = Animal.create('Mouse'); mouse.identify(); // mouse Note that an attempt to access the static method from an instance of the class results in an error. mouse.create('Monkey'); // Uncaught TypeError: mouse.create is not a function ES6 has not provided a way to define static properties like static methods even though there was a proposal for adding them to the language. Now, you should have a good understanding of JavaScript class in ES6 and how to apply it to develop custom types in your application.